
#define _CRT_SECURE_NO_WARNINGS
#include "Tools.h"
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <cstring>
#include <fstream>
#include <iostream>
#include <errno.h>
#include <string.h>
#if defined(WIN32) || defined(_WIN32)
#include <windows.h>
#include "gnufuncs.h"
#endif

using namespace std;


CTools * CTools::m_instance = NULL;

CTools::CTools()
{
        apppath = NULL;
#if defined(WIN32) || defined(_WIN32)
        char           temp[1024];
        GetModuleFileNameA(GetModuleHandleA(NULL), temp, 1024);
        *(strrchr(temp, '\\')) = '\0';
        apppath = new char[strlen(temp) + 2];
        strcpy(apppath, temp);
        strcat(apppath, "\\");
#endif
}

CTools::~CTools()
{
        map<string, const unsigned char *>::iterator     iter;
        for(iter = bmpMap.begin(); iter != bmpMap.end(); iter ++)
        {
                delete[] iter->second;
        }
        bmpMap.clear();
        if(apppath != NULL)
                delete [] apppath;
        m_instance = NULL;
        m_ofr.close();
}

CTools * CTools::Get(void)
{
        if(m_instance == NULL)
        {
                m_instance = new CTools();
        }
        if(m_instance == NULL)
        {
                throw("malloc failed\n");
        }
        return m_instance;
}

FILERES *  CTools::LoadFile(const char * filename)
{
        // TODO...
        map<string, const unsigned char *>::iterator     iter;
        iter = bmpMap.find(filename);
        FILERES * fr; 
        if(iter != bmpMap.end())
        {
                fr = (FILERES *)(iter->second);
                return fr;
        }

        unsigned char * buffer = NULL;
        streamoff       len;
        std::ifstream   file(filename, ios::in | ios::binary);
        if(file.fail())
        {
                PRINTF("No Such File:%s!\n", filename);
                return NULL;
        }
        file.seekg(0, ios::end);
        len = file.tellg();
        file.seekg(0, ios::beg);
        buffer = new unsigned char[static_cast<unsigned int>(len) + sizeof(int)];
        file.read((char *)buffer + sizeof(int), len);
        file.close();

        int     t = (int)len;
        memcpy(buffer, &t, sizeof(int));

        PRINTF("read %s\n", filename);
        bmpMap.insert(map<string, const unsigned char *>::value_type(filename, buffer));
        fr = (FILERES *)buffer;
        return fr;
}

FILERES * CTools::LoadRes(const char * resname)
{
        const char *    exttable[] = {"bmp", "png", "jpg"};        
        int             size = sizeof(exttable) / sizeof(exttable[0]);
        int             i;
        char            path[1024];
        char            temp[1024];
        char *          pos;
        const char *    p;

        if(resname == NULL)
                return NULL;

        memset(path, 0, sizeof(path));
        strcpy(path, "data\\");
        p = resname;
        pos = path + strlen(path);
        while(*p != '\0' && strlen(path) < 1000)
        {
                if(*p != '.')
                        pos[p - resname] = *p;
                else
                        pos[p - resname] = '\\';
                p++;
        }
        for(i=0; i<size; i++)
        {
                memset(temp, 0, sizeof(temp));
                snprintf(temp, 1023, "%s.%s", path, exttable[i]);
                if(IsFileExists(temp))
                {
                        return LoadFile(temp);
                }
        }
        
        return NULL;
}

int CTools::ResCount(const char * resname)
{
        return 0;
}

bool CTools::IsFileExists(const char * filename)
{
        if(filename == NULL)
                return false;
        ifstream        ifr(filename);
        if(!ifr)
                return false;
        ifr.close();
        return true;
#if 0
        if(access(filename, 0x04) == 0)
                return true;
        return false;
#endif
}

void CTools::DebugPRT(const char * file, const char * func, int line, const char * str, ...)
{
        va_list arglist;
        if(str == NULL || file == NULL || func == NULL)
        {
                throw "Debug! NULL string.\n";
                return;
        }
        const char *    p = strrchr(file, '\\');
        if(p == NULL)
        {
                p = file;
        }else{
                p ++;
        }
        time_t  t = time(NULL);
        struct  tm *    ctm = localtime(&t);
        char    buffer[4096];
        int     len;
        
        len = sprintf(buffer, "[%02d:%02d:%02d] [%s:%s:%05d] ", ctm->tm_hour, ctm->tm_min,
                ctm->tm_sec, p, func, line);
        va_start(arglist, str);
        vsprintf(buffer + len, str, arglist);
        va_end(arglist);
        fprintf(stdout, "%s", buffer);
        fflush(stdout);
        LogToFile(buffer);
        // cout << buffer << flush;
}
#if 0
#undef Debug
void    CTools::Debug(const char * fmt, ...)
{
        va_list arglist;
        va_start(arglist, fmt);
        vfprintf(stdout, fmt, arglist);
        va_end(arglist);
}
#endif

void CTools::SetLogFile(const char * filename)
{
        if(m_logfile == string(filename))
                return;
        m_ofr.close();
        if(filename == NULL)
        {
                m_logfile = string("");
        } else {
                m_logfile = string(filename);
                m_ofr.open(filename, ios::out);
        }
}

void CTools::LogToFile(const char * buffer)
{
        if(m_ofr)
        {
                m_ofr << buffer << endl << flush;
        }
}

const char * CTools::AppPath(void)
{
        return apppath;
}

double CTools::CurrentTime(void)
{
#if defined(WIN32) || defined(_WIN32)
        LARGE_INTEGER   litmp;
        LONGLONG        qt;
        double          dft;
        double          dff;
        
        QueryPerformanceFrequency(&litmp);
        dff = (double)litmp.QuadPart;

        QueryPerformanceCounter(&litmp);
        qt = litmp.QuadPart;

        dft = qt / dff;
        return dft;
#endif
        return 0.0;
}

ostream&  CTools::OutPRT(const char * file, const char * func, int line)
{
        if(file == NULL)
        {
                throw "Debug! NULL string.\n";
                return cout;
        }
#if defined(WIN32) || defined(_WIN32)
        const char *    p = strrchr(file, '\\');
#else
        const char *    p = strrchr(file, '/');
#endif
        if(p == NULL)
        {
                p = file;
        }else{
                p ++;
        }
        time_t  t = time(NULL);
        struct  tm *    ctm = localtime(&t); 
        char    buffer[1024];
        sprintf(buffer, "[%02d:%02d:%02d] [%s:%s:%05d] ", ctm->tm_hour, ctm->tm_min,
                ctm->tm_sec, p, func, line);
        cout << buffer << flush;
        LogToFile(buffer);
        return cout;
}

void CTools::dump(const void * data, int len)
{
        const char *    p = reinterpret_cast<const char *>(data);
        int             i;
        int             j;
        int             t;
        int             k;

        PRINTF("dump %d bytes from [%p]:\n", len,  data);
        for(i=0; i<len; i+=16)
        {
                printf("%08x: ", i);
                t = 16;
                if(i + 16 > len)
                        t = len - i;
                if(t == 16)
                {
                        for(k=i; k<len; k++)
                        {
                                if(p[k] != '\0')
                                        break;
                        }
                        if(k - i > 16 * 3)
                        {
                                k = k - (( k - i ) % 16);
                                printf(" 00 * %d lines\n", (k -i) / 16);
                                i = k - 16; 
                                continue;
                        }
                }
                for(j=0; j<t; j++)
                {
                        printf("%02x ", p[i+j] & 0xff);
                        if((j % 4) == 3)
                                printf(" ");
                }
                for(j=t; j<16; j++)
                {
                        printf("   ");
                        if((j % 4) == 3)
                                printf(" ");
                }
                printf("\t");
                for(j=0; j<t; j++)
                {
                        if((p[i+j] >= 36 && p[i+j] <= 126) || p[i+j] == '"')
                                printf("%c", p[i+j] & 0xff);
                        else
                                printf(".");
                }
                printf("\n");
        }
}

#if defined(WIN32) || defined(_WIN32)
const char * CTools::ShowLastError(void)
{
        static TCHAR  buff[1024];
        DWORD dw = GetLastError();
        LPVOID  lpMsgBuf;
        FormatMessageA(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                dw,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                (LPSTR) &lpMsgBuf,
                0,
                NULL
                );
        printf("%s\n", (char *)lpMsgBuf);
        fflush(stdout);
        lstrcpy(buff, (LPSTR)lpMsgBuf);
        LocalFree(lpMsgBuf) ;
        return buff;
}
#else
const char * CTools::ShowLastError(void)
{
        printf("%s\n", strerror(errno));
        fflush(stdout);
        return strerror(errno);
}
#endif




